	OUTPUT "sramtest.rom"
	
	
	org		0x4000
romheader:
	byte "AB"
	word BEGIN
	word 0,0,0,0,0,0


BEGIN:
	di
	im 		1
	ld 		sp,0xF380	
		
	;get current slot for page 1 to be able to come back later
	call	0x0138				;BIOS RSLREG
	;Function : Reads the primary slot register
	;Output   : A  - for the value which was read
	;		   33221100
	;		   ||||||- Pag 0 (#0000-#3FFF)
	;		   ||||--- Pag 1 (#4000-#7FFF)
	;		   ||----- Pag 2 (#8000-#BFFF)
	;		   ------- Pag 3 (#C000-#FFFF)	
	and		0x0c				;just interested on pag 1 (sram , if available, always from 0x4000 to 0x5FFF)
	rrca
	rrca
	ld		c,a
	ld		b,0x00
	ld		hl,0xFCC1
	add		hl,bc
	or		[hl]
	jp		p,current_slot_found			;jump if not subslots at current slot
	inc		hl
	inc		hl
	inc		hl
	inc		hl
	ld		c,a
	ld		a,[hl]
	and		0x0c
	or		c
current_slot_found:	
	ld		[current_slot_page1],a								;saving current slot/subslot for page1 to come back after checkings
	;current_slot_page1  - ExxxSSPP
	;		   |        || Primary  slotnumber  (00-11)
	;		   |        - Secundary slotnumber (00-11)
	;		   +----------- Expanded slot (0 = no, 1 = yes)
	
	
	
	;move code to memory
	ld		hl,relocatable_routines
	ld		de,0xc000
	ld		bc,relocatable_routines_end - relocatable_routines_on_memory
	ldir
	
	jp		relocatable_routines_on_memory
continue:
	ei
	jr		main_app


;texts
txt_found:
	db		14,"SRAM found at "
txt_not_found:
	db		15,"SRAM not found!"
	

main_app:
	call 	screen0
	
	ld		a,[sram_found]
	inc		a
	jr		z,display_found
	ld		hl,txt_not_found
	jp		display_set
display_found:
	ld		hl,txt_found
		
display_set:	
	;hl	already set
	call	update_buffer
	ld		de,80					;screen location
	call 	print_buffer


	ld		a,[sram_found]
	inc		a
	jr		nz,end

	ld		h,0
	ld		a,[sram_slot_page1]
	ld		l,a
	call	Bin2Bcd
	ld		de,buffer+1
	call	Bcd2HexAscii
	
	ld		a,6
	ld		[buffer],a				;screen location
	ld		de,120
	call	print_buffer

after_displaying_slot:

	call	update_sram_subrutine

	
	ld		h,0
	ld		a,[foo_value]
	ld		l,a
	call	Bin2Bcd
	ld		de,buffer+1
	call	Bcd2HexAscii	
	
	ld		a,6
	ld		[buffer],a				;screen location
	ld		de,160
	call	print_buffer

	

	
end:	
	halt
	jr		$





;support routines
screen0:
	xor		a
	call	0x005F			;screen 0
	call	0x00C3			;cls

	ret


;hl	src
update_buffer:
	ld		de,buffer
	ld		a,[hl]
	inc		a
	ld		b,0
	ld		c,a
	ldir

	ret

;de dest
print_buffer:
	ld		hl,buffer
	ld		a,[hl]
	inc		hl
	ld		b,0
	ld		c,a
	call	0x005c

	ret




;from http://de.comp.lang.assembler.x86.narkive.com/EjY9sEbE/z80-binary-to-ascii
;;--------------------------------------------------
;; Binary to BCD conversion
;;
;; Converts a 16-bit unsigned integer into a 6-digit
;; BCD number. 1181 Tcycles
;;
;; input: HL = unsigned integer to convert
;; output: C:HL = 6-digit BCD number
;; destroys: A,F,B,C,D,E,H,L
;;--------------------------------------------------
Bin2Bcd:
	LD BC, 16*256+0 ; handle 16 bits, one bit per iteration
	LD DE, 0
cvtLoop:
	ADD HL, HL
	LD A, E
	ADC A, A
	DAA
	LD E, A
	LD A, D
	ADC A, A
	DAA
	LD D, A
	LD A, C
	ADC A, A
	DAA
	LD C, A
	DJNZ cvtLoop
	EX DE,HL
	RET

;from http://de.comp.lang.assembler.x86.narkive.com/EjY9sEbE/z80-binary-to-ascii
;;----------------------------------------------------
;; Converts a 6-digit BCD number to a hex ASCII string
;;
;; input: DE = pointer to start of ASCII string
;; C:HL number to be converted
;; output: DE = pointer past end of ASCII string
;; destroys: A,F,D,E
;;-----------------------------------------------------
Bcd2HexAscii:
	LD A, C
	CALL cvtUpperNibble
	LD A, C
	CALL cvtLowerNibble
	LD A, H
	CALL cvtUpperNibble
	LD A, H
	CALL cvtLowerNibble
	LD A, L
	CALL cvtUpperNibble
	LD A, L
	JR cvtLowerNibble
cvtUpperNibble:
	RRA ; move upper nibble into lower nibble
	RRA
	RRA
	RRA
cvtLowerNibble:
	AND A, 0Fh ; isolate lower nibble
	ADD A, 90h ; old trick
	DAA ; for converting
	ADC A, 40h ; one nibble
	DAA ; to hex ASCII
	LD (DE), A
	INC DE
	RET



;end support routines
;----------------------------------------------------


relocatable_routines:

	org		0xc000
relocatable_routines_on_memory:	
	xor		a
	ld		[sram_slot_page1],a
	ld		[sram_found],a

	call	sram_detection
	
	ld		a,[current_slot_page1]
	call	change_slot_page1

	jp		continue



	
sram_detection:
	ld		b,4
sram_detection_loop:
	ld		a,b
	dec		a
	ld		d,a
	call	read_subslot_conf
	jr		nc,nosubslots							;nc ... not subslots
	push	bc
	call	change_slot_and_test
	pop		bc
comeback_from_nosubslots:
	ld		a,[sram_found]
	inc		a
	ret		z										;sram found , return

	djnz	sram_detection_loop					
	ret
	
	
read_subslot_conf:
	push	bc
	ld		c,a
	ld		b,0
	ld		hl,0xFCC1
	add		hl,bc
	ld		a,[hl]
	and		0x80
	or		c
	rlca	
	pop		bc

	ret
	
	
	
change_slot_and_test:
	ld		e,d
	ld		b,0x04
change_slot_and_test_loop:	
	ld		a,b
	dec		a
	rlca	
	rlca
	or		e
	or		0x80
	ld		d,a
	call	change_slot_page1
	push	de									;preserve e
	call	test_sram
	pop		de
	ret		z
	djnz	change_slot_and_test_loop

	ret


; a holds slot/subslot info
change_slot_page1:
	push	af
	push	hl
	push	de
	push	bc
	ld		h,0x40
	call	0x24				;ENASLT
	;Function : Switches indicated slot at indicated page on perpetual
	;Input    : A  - ExxxSSPP
	;				+-?------ 
	;		   H - Bit 6 and 7 must contain the page number (00-11)	
	pop		bc
	pop		de
	pop		hl
	pop		af

	ret



test_sram:
	ld		a,0x69
	ld		[0x5fff],a
	ld		a,0x4d
	ld		[0x5ffe],a

	ld		hl,0x5880
	ld		e,[hl]
	ld		a,e
	cpl		
	ld		[hl],a
	ld		a,[hl]
	cpl
	cp		e
	ret		nz
	ld		e,[hl]			;restore original value
	
	;checking if it's just RAM
	xor		a
	ld		[0x5fff],a
	ld		a,[hl]
	ld		e,a
	inc		a
	ld		[hl],a
	ld		a,[hl]
	cp		e
	ret		nz								;ret if it's RAM
	ld		a,0xff
	ld		[sram_found],a
	ld		a,d
	ld		[sram_slot_page1],a
	
	ret


nosubslots:
	ld		a,d
	call	change_slot_page1
	push	de									;preserve e
	call	test_sram
	pop		de
	
	jr		comeback_from_nosubslots
	ret


update_sram_subrutine:
	;set SRAM page
	di
	ld		a,[sram_slot_page1]
	call	change_slot_page1
	ei

	;activate SRAM
	ld		a,0x69
	ld		[0x5fff],a
	ld		a,0x4d
	ld		[0x5ffe],a

	;operations on SRAM 
	ld		a,[0x4000]
	inc		a
	ld		[foo_value],a
	ld		[0x4000],a

	;deactivate SRAM
	xor		a
	ld		[0x5fff],a

	;come back to normal page
	di
	ld		a,[current_slot_page1]
	call	change_slot_page1
	ei

	ret


relocatable_routines_end:



	org	0xc000	
mem_start:				equ		relocatable_routines_end
current_slot_page1:		equ		mem_start				;1 byte
sram_slot_page1:		equ		current_slot_page1 	+ 1	;1 byte
sram_found:				equ		sram_slot_page1 	+ 1	;1 byte
foo_value:				equ		sram_found 			+ 1	;1 byte
buffer:					equ		foo_value			+ 1 ;30 bytes
tmp_code:				equ		buffer 				+ 30;x bytes


	ds      0x4000 - (relocatable_routines_end-relocatable_routines_on_memory) - (relocatable_routines - romheader),0FFh       ; Filled up 16KB

